/********************************************************************
//      parsetree.c
//      
//      Copyright 2010 Adam Clark 
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.
**********************************************************************/

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>

#include "parsetree.h"

/* ================================================================ */

/*
 * -- Internal Functions
 *    ------------------
 */

static void panic (char *str)
{
	fprintf (stderr, "%s!!\n", str);
	exit (1);
}

static void *alloc (size_t size, char *msg)
/*******************************************************************
 * All functions in this source assume that the structure returned
 * by this routine are pre-set with 0 in all elements.  All 
 * supporting types assume a 0 element is an appropriate default.
 *******************************************************************/
{
	void *rv = malloc(size);
	if (!rv) panic(msg);
	memset (rv, 0, size);
	return rv;
}

/* ================================================================ */

/*
 * -- Literals
 *    --------
 */

Literal *MakeBoolLiteral (int l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal), 
			"Unable to allocate BoolLiteral");
			
	rv->literalType = LIT_BOOL;
	rv->intVal = l;
	return rv;
}

Literal *MakeCharLiteral (char l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal), 
			"Unable to allocate CharLiteral");
	
	rv->literalType = LIT_CHAR;
	rv->charVal = l;
	return rv;
}

Literal *MakeStringLiteral (char *l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate StringLiteral");
	
	rv->literalType = LIT_STRING;
	rv->stringVal = l;
	return rv;
}

Literal *MakeShortLiteral (short l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate ShortLiteral");
	
	rv->literalType = LIT_SHORT;
	rv->shortVal = l;
	return rv;
}

Literal *MakeIntLiteral (int l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal), 
			"Unable to allocate IntLiteral");
	
	rv->literalType = LIT_INT;
	rv->intVal = l;
	return rv;
}

Literal *MakeLongLiteral (long l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate LongLiteral");
	
	rv->literalType = LIT_LONG;
	rv->longVal = l;
	return rv;
}

Literal *MakeLongLongLiteral (long long l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate LongLongLiteral");
	
	rv->literalType = LIT_LONGLONG;
	rv->longlongVal = l;
	return rv;
}

Literal *MakeUCharLiteral (unsigned char l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate UCharLiteral");
	
	rv->literalType = LIT_UCHAR;
	rv->ucharVal = l;
	return rv;
}

Literal *MakeUShortLiteral (unsigned short l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate UShortLiteral");
	
	rv->literalType = LIT_USHORT;
	rv->ushortVal = l;
	return rv;
}

Literal *MakeUIntLiteral (unsigned int l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate UIntLiteral");
	
	rv->literalType = LIT_UINT;
	rv->uintVal = l;
	return rv;
}

Literal *MakeULongLiteral (unsigned long l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate ULongLiteral");
	
	rv->literalType = LIT_ULONG;
	rv->ulongVal = l;
	return rv;
}

Literal *MakeULongLongLiteral (unsigned long long l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate ULongLongLiteral");
	
	rv->literalType = LIT_ULONGLONG;
	rv->ulonglongVal = l;
	return rv;
}

Literal *MakeFloatLiteral (float l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate FloatLiteral");
	
	rv->literalType = LIT_FLOAT;
	rv->floatVal = l;
	return rv;
}

Literal *MakeDoubleLiteral (double l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate DoubleLiteral");
	
	rv->literalType = LIT_DOUBLE;
	rv->doubleVal = l;
	return rv;
}

Literal *MakeLongDoubleLiteral (long double l)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate LongDoubleLiteral");
	
	rv->literalType = LIT_LONGDOUBLE;
	rv->longdoubleVal = l;
	return rv;
}

Literal *MakeNullLiteral (void)
{
	Literal *rv = (Literal *)alloc(sizeof(Literal),
			"Unable to allocate NullLiteral");
	
	rv->literalType = LIT_NULL;
	return rv;
}

/* ================================================================ */

/*
 * -- Identifiers, & Arrays
 *    ---------------------
 */

Identifier *NewIdentifier (IdentType t, PrimType p, char *n)
{
	Identifier *rv = alloc(sizeof(Identifier), 
			"Unable to allocate new Identifier");
	
	rv->type = t;
	rv->prim = p;
	rv->ident = n;
	return rv;
}

Identifier *Ident_AddArrayDefnCurr (Identifier *rv)
{
	rv->index[rv->numIdx] = alloc(sizeof(ArraySquares), 
			"Unable to allocate new Array Access/Squares");
	rv->index[rv->numIdx]->type = ix_None;
	rv->numIdx ++;
	return rv;
}

Identifier *Ident_AddArrayDefnCount (Identifier *rv, long n)
{
	long l;
	
	for (l = 0; l < n; l++)
		Ident_AddArrayDefnCurr (rv);
	return rv;
}

Identifier *Ident_AddArrayAccessCurr (Identifier *rv, Expression *e)
{
	rv->index[rv->numIdx] = alloc(sizeof(ArraySquares), 
			"Unable to allocate new Array Access/Squares");
	rv->index[rv->numIdx]->type = ix_Expr;
	rv->index[rv->numIdx]->expr = e;
	rv->numIdx ++;
	return rv;
}

void Ident_SetIdentType (Identifier *n, IdentType i)
{
	n->type = i;
}

void Ident_SetPrimType (Identifier *n, PrimType p)
{
	n->prim = p;
}

ArraySquaresList *AppendSquares (ArraySquaresList *rv, Expression *e)
{
	ArraySquaresList *tmp = alloc(sizeof(ArraySquaresList), 
			"Unable to allocate new element in ArraySquaresList");
	ArraySquares *wrk = alloc(sizeof(ArraySquares),
			"Unable to allocate new ArraySquares in ArraySquaresList");
	ArraySquaresList *n = rv;
	
	wrk->expr = e;
	wrk->type = ix_None;
	tmp->curr = wrk;
	
	if (!rv) return tmp;
	
	while (n->next) {
		n = n->next;
	};
	
	n->next = tmp;
	return rv;
}

Identifier *ConvertArraySquaresList (Identifier *rv, ArraySquaresList *l)
{
	ArraySquaresList *wrk;
	
	wrk = l;
	while (l) {
		rv->index[rv->numIdx++] = l->curr;
		l=l->next;
		free(wrk);
		wrk = l;
	}
	return rv;
}

FormalParameter *MakeFormalParameter (Expression *t, Identifier *i)
{
	FormalParameter *rv = alloc(sizeof(FormalParameter),
			"Unable to allocate FormalParameter");
	
	rv->type = t;
	rv->ident = i;
	return rv;
}

FormalParameter *AppendFormalParameter (FormalParameter *rv, FormalParameter *n)
{
	FormalParameter *wrk = rv;
	if (!rv) return n;
	while (wrk->next) wrk = wrk->next;
	wrk->next = n;
	return rv;
}

/* ================================================================ */

/*
 * -- Modifiers
 *    ---------
 */

Modifier Modifier_AddFlag (Modifier rv, ModListType f)
{
	return rv & (1 << f);
}

/* ================================================================ */

/*
 * -- Expressions
 *    -----------
 */

Expression *MakeExpr (int op)
{
	Expression *rv = alloc(sizeof(Expression), 
			"Unable to allocate Expression");
	
	rv->operation = op;
	return rv;
}

Expression *Expr_SetLeftExprType (Expression *rv, ExprType t)
{
	rv->leftType = t;
	return rv;
}

Expression *Expr_SetLeftExpr (Expression *rv, Expression *l)
{
	rv->leftSideExpr = l;
	rv->leftType = ex_Expr;
	return rv;
}

Expression *Expr_SetLeftLiteral (Expression *rv, Literal *l)
{
	rv->leftSideLiteral = l;
	rv->leftType = ex_Literal;
	return rv;
}

Expression *Expr_SetLeftIdent (Expression *rv, Identifier *l)
{
	rv->leftSideIdent = l;
	rv->leftType = ex_Ident;
	return rv;
}

Expression *Expr_SetRightExprType (Expression *rv, ExprType t)
{
	rv->rightType = t;
	return rv;
}

Expression *Expr_SetRightExpr (Expression *rv, Expression *r)
{
	rv->rightSideExpr = r;
	rv->rightType = ex_Expr;
	return rv;
}

Expression *Expr_SetRightLiteral (Expression *rv, Literal *r)
{
	rv->rightSideLiteral = r;
	rv->rightType = ex_Literal;
	return rv;
}

Expression *Expr_SetRightIdent (Expression *rv, Identifier *r)
{
	rv->rightSideIdent = r;
	rv->rightType = ex_Ident;
	return rv;
}

Expression *Expr_AddNextExpr (Expression *rv, Expression *n)
{
	Expression *w = rv;
	if (!rv) return n;
	while (w->next) w = w->next;
	w->next = n;
	return rv;
}

Expression *Expr_SetArgList (Expression *rv, Expression *a)
{
	rv->argList = a;
	return rv;
}

Expression *Expr_SetLeftType (Expression *rv, ExprType t)
{
	rv->leftType = t;
	return rv;
}

Expression *Expr_SetRightType (Expression *rv, ExprType t)
{
	rv->rightType = t;
	return rv;
}

Expression *Expr_AddThenElse (Expression *rv, Expression *t, Expression *e)
{
	rv->rightSideExpr = t;
	rv->rightType = ex_Expr;
	rv->elsePart = e;
	return rv;
}

Expression *Expr_SetOp (Expression *rv, int op)
{
	rv->operation = op;
	return rv;
}

Expression *Expr_SetIdentTypeLeft (Expression *n, IdentType i)
{
	if (n->leftType == ex_Ident)
		Ident_SetIdentType (n->leftSideIdent, i);
	return n;
}

Expression *Expr_SetPrimTypeLeft (Expression *n, PrimType p)
{
	if (n->leftType == ex_Ident)
		Ident_SetPrimType (n->leftSideIdent, p);
	return n;
}

Expression *Expr_SetIdentTypeRight (Expression *n, IdentType i)
{
	if (n->rightType == ex_Ident)
		Ident_SetIdentType (n->rightSideIdent, i);
	return n;
}

Expression *Expr_SetPrimTypeRight (Expression *n, PrimType p)
{
	if (n->rightType == ex_Ident)
		Ident_SetPrimType (n->rightSideIdent, p);
	return n;
}

Expression *Expr_SetModifiers (Expression *rv, Modifier m)
{
	rv->modifiers = m;
	return rv;
}

/* ================================================================ */

/*
 * -- Statments & Blocks
 *    ------------------
 */

Block *MakeBlock (Statement *s)
{
	Block *rv = alloc(sizeof(Block), "Unable to allocate Block");
		
	rv->stmt = s;
	return rv;
}

BreakStmt *MakeBreakStmt (Identifier *i)
{
	BreakStmt *rv = alloc(sizeof(BreakStmt), 
			"Unable to allocate BreakStmt");
		
	rv->ident = i;
	return rv;
}

CatchClause *MakeCatchClause (FormalParameter *p, Block *b)
{
	CatchClause *rv = alloc(sizeof(CatchClause),
			"Unable to allocate CatchClause");
	
	rv->param = p;
	rv->block = b;
	return rv;
}

ContinueStmt *MakeContinueStmt (Identifier *i)
{
	ContinueStmt *rv = alloc(sizeof(ContinueStmt),
			"Unable to allocate ContinueStmt");
	
	rv->ident = i;
	return rv;
}

DoStmt *MakeDoStmt (Statement *s, Expression *c)
{
	DoStmt *rv = alloc(sizeof(DoStmt),
			"Unable to allocate DoStmt");
	
	rv->stmt = s;
	rv->check = c;
	return rv;
}

IfStmt *MakeIfStmt (Expression *c, Statement *t, Statement *e)
{
	IfStmt *rv = alloc(sizeof(IfStmt),
			"Unable to allocate IfStmt");
	
	rv->cond = c;
	rv->thenPart = t;
	rv->elsePart = e;
	return rv;
}

ForStmt *MakeForStmt (Expression *i, Expression *c, Expression *u, Statement *s)
{
	ForStmt *rv = alloc(sizeof(ForStmt),
			"Unable to allocate ForStmt");
	
	rv->init = i;
	rv->check = c;
	rv->update = u;
	rv->stmt = s;
	return rv;
}

ReturnStmt *MakeReturnStmt (Expression *e)
{
	ReturnStmt *rv = alloc(sizeof(ReturnStmt),
			"Unable to allocate ReturnStmt");
	
	rv->expr = e;
	return rv;
}

SwitchGroup *MakeSwitchGroup (SwitchLabel *l, Statement *s)
{
	SwitchGroup *rv = alloc(sizeof(SwitchGroup),
			"Unable to allocate SwitchGroup");
	
	rv->labels = l;
	rv->stmt = s;
	return rv;
}

SwitchStmt *MakeSwitchStmt (Expression *e, SwitchGroup *g)
{
	SwitchStmt *rv = alloc(sizeof(SwitchStmt),
			"Unable to allocate SwitchStmt");
	
	rv->expr = e;
	rv->groups = g;
	return rv;
}

SynchedStmt *MakeSynchedStmt (Expression *e, Block *b)
{
	SynchedStmt *rv = alloc(sizeof(SynchedStmt),
			"Unable to allocate SynchedStmt");
	
	rv->expr = e;
	rv->block = b;
	return rv;
}

ThrowStmt *MakeThrowStmt (Expression *e)
{
	ThrowStmt *rv = alloc(sizeof(ThrowStmt),
			"Unable to allocate ThrowStmt");
	
	rv->expr = e;
	return rv;
}

TryStmt *MakeTryStmt (Block *b, CatchClause *c, Block *f)
{
	TryStmt *rv = alloc(sizeof(TryStmt),
			"Unable to allocate TryStmt");
	
	rv->block = b;
	rv->catch = c;
	rv->finally = f;
	return rv;
}

WhileStmt *MakeWhileStmt (Expression *c, Statement *s)
{
	WhileStmt *rv = alloc(sizeof(WhileStmt),
			"Unable to allocate WhileStmt");
	
	rv->check = c;
	rv->stmt = s;
	return rv;
}

CatchClause *AppendCatchClause (CatchClause *rv, CatchClause *c)
{
	CatchClause *wrk = rv;
	
	if (!rv) return c;
	while (wrk->next) wrk = wrk->next;
	wrk->next = c;
	return rv;
}

SwitchGroup *AppendSwitchGroup (SwitchGroup *rv, SwitchGroup *n)
{
	SwitchGroup *wrk = rv;
	SwitchGroup *tmp = alloc(sizeof(SwitchGroup),
			"Unable to allocate SwitchGroup");
	
	if (!rv) return tmp;
	while (wrk->next) wrk = wrk->next;
	wrk->next = tmp;
	return rv;
}

SwitchLabel *AppendSwitchLabel (SwitchLabel *rv, Expression *l)
{
	SwitchLabel *wrk = rv;
	SwitchLabel *tmp = alloc(sizeof(SwitchLabel),
			"Unable to allocate SwitchLabel");
	
	tmp->label = l;
	if (!rv) return tmp;
	while (wrk->next) wrk = wrk->next;
	wrk->next = tmp;
	return rv;
}

Statement *MakeStmt (void)
{
	return alloc(sizeof(Statement), "Unable to allocate Statement");
}

Statement *Stmt_SetNextStmt (Statement *rv, Statement *n)
{
	Statement *wrk = rv;
	
	if (!rv) return n;
	while (wrk->next) wrk = wrk->next;
	wrk->next = n;
	return rv;
}

Statement *Stmt_SetLabel (Statement *rv, Identifier *l)
{
	rv->label = l;
	return rv;
}

Statement *Stmt_SetBlockStmt (Statement *rv, Block *b)
{
	rv->type = st_Block;
	rv->block = b;
	return rv;
}

Statement *Stmt_SetBreakStmt (Statement *rv, BreakStmt *b)
{
	rv->type = st_BreakStmt;
	rv->breakStmt = b;
	return rv;
}

Statement *Stmt_SetContinueStmt (Statement *rv, ContinueStmt *c)
{
	rv->type = st_ContinueStmt;
	rv->continueStmt = c;
	return rv;
}

Statement *Stmt_SetIfStmt (Statement *rv, IfStmt *i)
{
	rv->type = st_IfStmt;
	rv->ifStmt = i;
	return rv;
}

Statement *Stmt_SetDoStmt (Statement *rv, DoStmt *d)
{
	rv->type = st_DoStmt;
	rv->doStmt = d;
	return rv;
}

Statement *Stmt_SetExprStmt (Statement *rv, Expression *e)
{
	rv->type = st_ExprStmt;
	rv->exprStmt = e;
	return rv;
}

Statement *Stmt_SetForStmt (Statement *rv, ForStmt *f)
{
	rv->type = st_ForStmt;
	rv->forStmt = f;
	return rv;
}

Statement *Stmt_SetReturnStmt (Statement *rv, ReturnStmt *r)
{
	rv->type = st_ReturnStmt;
	rv->returnStmt = r;
	return rv;
}

Statement *Stmt_SetSwitchStmt (Statement *rv, SwitchStmt *s)
{
	rv->type = st_SwitchStmt;
	rv->switchStmt = s;
	return rv;
}

Statement *Stmt_SetSynchedStmt (Statement *rv, SynchedStmt *s)
{
	rv->type = st_SynchedStmt;
	rv->synchedStmt = s;
	return rv;
}

Statement *Stmt_SetThrowStmt (Statement *rv, ThrowStmt *t)
{
	rv->type = st_ThrowStmt;
	rv->throwStmt = t;
	return rv;
}

Statement *Stmt_SetTryStmt (Statement *rv, TryStmt *t)
{
	rv->type = st_TryStmt;
	rv->tryStmt = t;
	return rv;
}

Statement *Stmt_SetWhileStmt (Statement *rv, WhileStmt *w)
{
	rv->type = st_WhileStmt;
	rv->whileStmt = w;
	return rv;
}

Statement *Stmt_SetVarDeclStmt (Statement *rv, Expression *v)
{
	rv->type = st_VarDecl;
	rv->exprStmt = v;
	return rv;
}

/* ================================================================ */

/*
 * -- Packages, Imports, & Types
 *    --------------------------
 */

MethodDecl *MakeMethodDecl(Identifier *i, FormalParameter *p)
{
	MethodDecl *rv = alloc(sizeof(MethodDecl),
			"Unable to allocate MethodDecl");
	
	rv->name = i;
	rv->params = p;
	return rv;
}

Method *MakeMethod(MethodType tp, Modifier m, Expression *r, 
		MethodDecl *d, Expression *t)
{
	Method *rv = alloc(sizeof(Method),
			"Unable to allocate Method");

	rv->type = tp;
	rv->flags = m;
	rv->retType = r;
	rv->decl = d;
	rv->throws = t;
	return rv;
}

Method *Meth_SetBody (Method *rv, Block *b)
{
	rv->body = b;
	return rv;
}

Method *Meth_SetType (Method *rv, MethodType t)
{
	rv->type = t;
	return rv;
}

MethodDecl *MethD_AddArraySquares (MethodDecl *rv)
{
	rv->name = Ident_AddArrayDefnCurr(rv->name);
	return rv;
}

ClassMember *MakeEmptyClassMember(void)
{
	ClassMember *rv = alloc(sizeof(ClassMember),
			"Unable to allocate ClassMember");
	return rv;
}

ClassMember *cmbr_SetField (ClassMember *rv, Expression *f)
{
	rv->field = f;
	rv->type = cm_Field;
	return rv;
}

ClassMember *cmbr_SetMethod (ClassMember *rv, Method *m)
{
	rv->meth = m;
	rv->type = cm_Method;
	return rv;
}

ClassMember *cmbr_SetInitializer (ClassMember *rv, Block *b)
{
	rv->init = b;
	rv->type = cm_Initializer;
	return rv;
}

ClassMember *cmbr_SetNextCMbr (ClassMember *rv, ClassMember *n)
{
	ClassMember *wrk = rv;
	if (!rv) return n;
	while (wrk->next) wrk = wrk->next;
	wrk->next = n;
	return rv;
}

TypeDecl *MakeEmptyTypeDecl (void)
{
	TypeDecl *rv = alloc(sizeof(TypeDecl),
			"Unable to allocate TypeDecl");
	return rv;
}

TypeDecl *Type_SetClass (TypeDecl *rv, Modifier m, Identifier *i, 
		Expression *s, Expression *f, ClassMember *b)
{
	rv->flags = m;
	rv->name = i;
	rv->super = s;
	rv->interface = f;
	rv->body = b;
	return rv;
}

TypeDecl *Type_SetInterface (TypeDecl *rv, Modifier m, Identifier *i, 
		Expression *f, ClassMember *b)
{
	rv->flags = m;
	rv->name = i;
	rv->interface = f;
	rv->body = b;
	return rv;
}

TypeDecl *Type_SetNextTypeDecl (TypeDecl *rv, TypeDecl *n)
{
	TypeDecl *wrk = rv;
	if (!rv) return n;
	while (wrk->next) wrk = wrk->next;
	wrk->next = n;
	return rv;
}

CompUnit *MakeCompUnit (Expression *p, Expression *i, TypeDecl *t)
{
	CompUnit *rv = alloc(sizeof(CompUnit),
			"Unable to allocate CompUnit");
	
	rv->pkg = p;
	rv->imp = i;
	rv->typ = t;
	return rv;
}
